package cn.com.artemis.security;

import cn.com.artemis.security.properties.OAuth2Properties;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.List;

/**
 * RBAC服务
 * @author enbool
 */
public class RbacService {
    private WhiteList whiteList;
    private PermissionService permissionService;
    private OAuth2Properties oAuth2Properties;
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    public RbacService(PermissionService permissionService, OAuth2Properties oAuth2Properties, WhiteList whiteList) {
        this.permissionService = permissionService;
        this.oAuth2Properties = oAuth2Properties;
        this.whiteList = whiteList;
    }

    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        if (!authentication.isAuthenticated() || authentication instanceof AnonymousAuthenticationToken) {
            // 未登录或匿名用户
            return false;
        }

        if (!oAuth2Properties.getUseRBAC()) {
            // 不使用RBAC
            return true;
        }

        String uri = request.getRequestURI();

        String[] nonCheckPermissionUrls = whiteList.nonCheckPermission();
        // 白名单，不需要权限检查的
        if (nonCheckPermissionUrls.length > 0) {
            for (String nonCheckPermissionUrl : nonCheckPermissionUrls) {
                if (antPathMatcher.match(nonCheckPermissionUrl, uri)) {
                    return true;
                }
            }
        }

        boolean hasPermission = false;

        Principal principal = request.getUserPrincipal();
        if (principal == null) {
            return false;
        }
        String username = principal.getName();
        if (username == null) {
            return false;
        }

        List<String> permissions = permissionService.loadUserPermissions(username);

        if(permissions.isEmpty()){
            return false;
        }

        String method = request.getMethod();
        int ordinal = RequestMethod.valueOf(method).ordinal();
        for (String permission : permissions) {
            String[] method_url = permission.split(" ");
            // method优先级比较  GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
            if (RequestMethod.valueOf(method_url[0]).ordinal() < ordinal) {
                continue;
            }
            if (antPathMatcher.match(method_url[1], uri)) {
                hasPermission = true;
                break;
            }

        }

        return hasPermission;
    }
}